package com.imooc.course.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

/**
 * LoginAdminGatewayFilter只负责admin.vue页面的拦截
 */
@Component
public class LoginAdminGatewayFilter implements GatewayFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(LoginAdminGatewayFilter.class);

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        log.info("请求：{}", path);

        //不是前往admin.vue页面的不拦截
        if (!path.contains("admin")) {
            return chain.filter(exchange);
        }

        //部分前往admin.vue中的请求也不需要拦截
        ArrayList<String> notContainPathList = new ArrayList<>();
        notContainPathList.add("/system/admin/user/login");
        notContainPathList.add("/system/admin/user/logout");
        notContainPathList.add("/system/admin/kaptcha");
        for (int i = 0; i < notContainPathList.size(); i++) {
            if (path.contains(notContainPathList.get(i))) {
                log.info("不需要拦截的路径：{}，请求被通过；", notContainPathList.get(i));
                return chain.filter(exchange);
            }
        }

        //获取请求头中的token
        String token = exchange.getRequest().getHeaders().getFirst("token");

        //token来自共享session，如果token为空，则表示从未登录
        if (StringUtils.isEmpty(token)) {
            log.info("未获取到token令牌，token:{}，请求将被拦截；", token);
            exchange.getResponse().setStatusCode(HttpStatus.REQUEST_TIMEOUT);
            return exchange.getResponse().setComplete();
        }

        //获取到token令牌后，则需要验证是否有效，通过方可登录

        //从共享session获取token的value
        String tokenValue = (String)redisTemplate.opsForValue().get(token);

        if (StringUtils.isEmpty(tokenValue)) {
            log.warn("无效的token令牌，token:{}，请求将被拦截；", token);
            exchange.getResponse().setStatusCode(HttpStatus.REQUEST_TIMEOUT);
            return exchange.getResponse().setComplete();
        } else {
            log.info("token有效，用户已经登录:{}", tokenValue);

            // 增加权限校验，gateway里没有LoginUserDto，所以全部用JSON操作
            JSONObject loginUserJson = JSON.parseObject(tokenValue);
            // loginUserJson它已经被 JSON.parseObject()方法转换为对象了，只不过不是原来的那个对象，而是JSONObject类型。

            // 如果用户在token失效之前再次访问服务器，则将token时效重新设置为3600秒
            redisTemplate.opsForValue().set(token, JSON.toJSONString(loginUserJson), 3600, TimeUnit.SECONDS);

//            本想page页面也作后端拦截，
//            但数据表的page字段值只适用前端路由拦截，无法兼容后端。
//            page字段值"/system/user"，适用于前端拦截。
//            后端需要的page字段值"/system/admin/user"
//            JSONArray resources = loginUserJson.getJSONArray("resources");
//            Boolean boolePage = false;
//            for (int i = 0; i < resources.size(); i++) {
//                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(resources.get(i)));
//                String page = jsonObject.getString("page");
//                if (page == null) {
//                    continue;
//                }
//                if (path.contains(page)) {
//                    boolePage = true;
//                    log.info("拥有{}权限", page);
//                    break;
//                }
//            }
//
//            if (boolePage == false) {
//                log.warn("拦截:无权限的请求{}",path);
//                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//                return exchange.getResponse().setComplete();
//            }

            JSONArray requests = loginUserJson.getJSONArray("requests");
            Boolean boole = false;
            for (int i = 0; i < requests.size(); i++) {
                String requestStr = (String) requests.get(i);
                if (path.contains(requestStr)) {
                    boole = true;
                    log.info("拥有{}权限", requestStr);
                    break;
                }
            }

            if (boole == false) {
                log.warn("拦截:无权限的请求{}",path);
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        //这个为过滤器器顺序
        //spring的gateway内还有许多内置的filter，它们的顺序好像都是负数。
        return 1;
    }
}
